﻿#include "StdAfx.h"
#include "MemPool.h"
#include "MemBlock.h"
#include "MemPoolUnit.h"

//#define	ALIGN_WORD(i) (i%8==0 ? i : ((i/8)+1)*8)

int					CMemPool::thePoolID = 0;
CCriticalSection	CMemPool::theCs;

CMemPool::CMemPool(int unitSize, int unitPerBlock)
	: m_unitSize(unitSize),
	m_unitCountPerBlock(unitPerBlock),
	m_poolID(getPoolID()), //为当前内存池获取一个全局ID.
	m_usableBlockCount(0), //初始不分配内存块，所以没有可用的快
	m_totalBlockCount(0)  //初始不分配内存块
{
}
//清理内存块
CMemPool::~CMemPool(void)
{
	auto nCount = m_allBlocks.GetCount();
	for (auto i = 0; i < nCount; i++)
	{
		delete static_cast<CMemBlock *>(m_allBlocks[i]);
	}
}

// 获取一个内存块，包含有多个子单元
void CMemPool::alloc(CMemPoolUnit ** pUnit)
{
	int			blockID;
	CMemBlock	* pBlock;

	// 如果没有可用块，则生成
	if (m_usableBlockCount == 0)
	{
		allocBlock();
	}

	// 获取一个可用块
	rw_Cs.Lock();
	blockID = m_usableBlocks.GetHead();
	pBlock = static_cast<CMemBlock *>(m_allBlocks[blockID]);

	// 获取一个可用单元
	pBlock->alloc(pUnit);
	(*pUnit)->Init(m_poolID, blockID, this);

	// 如果块被用完，应被移出可用队列
	if (pBlock->isFull())
	{
		m_usableBlocks.RemoveHead();
		m_usableBlockCount--;
	}
	rw_Cs.Unlock();
}

// 释放一个单元
void CMemPool::free(CMemPoolUnit * pUnit)
{
	bool		wasFull;
	CMemBlock	* pBlock;

	// 释放单元
	rw_Cs.Lock();
	pBlock = static_cast<CMemBlock *>(m_allBlocks[pUnit->GetBlockID()]);
	wasFull = pBlock->isFull();
	pBlock->free(pUnit);

	// 如需要更改对应块状态
	if (wasFull)
	{
		m_usableBlocks.AddTail(pUnit->GetBlockID());
		m_usableBlockCount++;
	}
	rw_Cs.Unlock();
}

// 生成一个可用块
void CMemPool::allocBlock()
{
	int			blockID;
	CMemBlock	* pBlock;

	// 获取一个块，里面包含m_unitPerBlock个对象单元，每个对象单元大小m_unitSize
	pBlock = new CMemBlock(m_unitSize, m_unitCountPerBlock);

	// 插入总块数队列
	blockID = m_allBlocks.Add(static_cast<void *>(pBlock));
	m_usableBlocks.AddTail(blockID);	//插入可用块队列
	m_usableBlockCount++;
	m_totalBlockCount++;
}